<template>
  <component
    :id="mConfig.id"
    class="page-node-dom"
    :is="mConfig.mpdConfig.component"
    :class="mpdTransformClass"
    :style="mpdTransformStyle"
    v-if="mpdTransformIf"
    v-show="mpdTransformShow"
    v-bind="mpdTransformAttr"
    v-on="mpdTransformEvent"
  >
    <template v-if="mpdTransformText">{{ mpdTransformText }}</template>
    <slot></slot>
    <template v-for="item1 in mConfig.mpdConfig.slot" v-slot:[item1.title]="slotValue">
      <page-node-dom
        v-for="(item2, index2) in item1.children"
        :mConfig="item2"
        :slotValue="slotValue"
        :key="index2"
      ></page-node-dom>
    </template>
  </component>
</template>

<script>
import { isArray } from '@/util/utils'
import { isCssVariableName } from '@/util/regexUtil'
import { fieldToCamel } from '@/util/utils'
import Vue from 'vue'

export default {
  name: 'PageNodeDom',
  props: {
    // 当前节点配置
    mConfig: {
      type: Object,
      required: true
    },
    // 如果是被当成Slot，才会有值
    slotValue: {
      type: Object,
      default() {
        return {}
      }
    }
  },
  inject: ['selectPageNodeDom', 'mpdPageValue'],
  data() {
    return {
      // 组件内部使用的值
      mValue: {}
    }
  },
  computed: {
    // 转换v-if指令
    mpdTransformIf() {
      return this.mpdTransformIfOrShowHandle(this.mConfig.mpdConfig.vIf)
    },
    // 转换v-show指令
    mpdTransformShow() {
      return this.mpdTransformIfOrShowHandle(this.mConfig.mpdConfig.vShow)
    },
    // 文本内容转换
    mpdTransformText() {
      if (this.mConfig.mpdConfig.text) {
        try {
          return eval('`' + this.mConfig.mpdConfig.text + '`').replace(/undefined|null/g, '')
        } catch (error) {
          console.error('text值转换错误（可以忽略）', error)
        }
      } else {
        return null
      }
    },
    // class内容转换
    mpdTransformClass() {
      if (this.mConfig.mpdConfig.class) {
        try {
          return eval('`' + this.mConfig.mpdConfig.class + '`').replace(/undefined|null/g, '')
        } catch (error) {
          console.error('class值转换错误（可以忽略）', error)
        }
      } else {
        return null
      }
    },
    // style内容转换
    mpdTransformStyle() {
      if (isArray(this.mConfig.mpdConfig.style)) {
        try {
          const obj = {}
          this.mConfig.mpdConfig.style.forEach(item => {
            if (isCssVariableName(item.key) && item.value) {
              const oKey = eval('`' + item.key + '`').replace(/undefined|null/g, '')
              const oValue = eval('`' + item.value + '`').replace(/undefined|null/g, '')
              obj[oKey] = oValue
            }
          })
          return obj
        } catch (error) {
          console.error('style值转换错误（可以忽略）', error)
        }
      } else {
        return null
      }
    },
    // 转换属性参数，让其可以访问当前item的值
    mpdTransformAttr() {
      const attrObj = this.mConfig.mpdConfig.attr
      const newAttrObj = {}
      for (const key in attrObj) {
        try {
          const element = attrObj[key]
          if (typeof element === 'string' && element.startsWith('$:')) {
            newAttrObj[key] = eval('(' + element.replace('$:', '') + ')')
          } else {
            newAttrObj[key] = element
          }
        } catch (exception) {
          console.error('attr值转换错误(这个错误可以忽略)', this.mConfig, exception)
        }
      }
      // 加入配置的model值
      const modelObj = this.mConfig.mpdConfig.model
      for (const key in modelObj) {
        try {
          if (newAttrObj.hasOwnProperty(key)) {
            console.error('发现model重复值，请检查配置：', this.mConfig, key)
          }
          newAttrObj[key] = eval(modelObj[key])
        } catch (exception) {
          console.error('model值转换错误(这个错误可以忽略)', this.mConfig, exception)
        }
      }
      return newAttrObj
    },
    // 转换事件参数，让其内部调用可以正常获取参数
    mpdTransformEvent() {
      const eventObj = this.mConfig.mpdConfig.event
      const newEventObj = {}
      const _this = this
      for (const key in eventObj) {
        const element = eventObj[key]
        newEventObj[key] = function() {
          ;(function() {
            const evalResult = eval(element)
            if (typeof evalResult === 'function') {
              evalResult.call(_this, ...arguments)
            }
          }.call(_this, ...arguments))
        }
      }
      // 加入配置的model值
      const modelObj = this.mConfig.mpdConfig.model
      for (const key in modelObj) {
        try {
          if (newEventObj.hasOwnProperty(key)) {
            console.error('发现model绑定事件重复值，请检查配置：', this.mConfig, key)
          } else {
            const element = modelObj[key]
            // 检查组件内部是否修改了value的默认事件
            const componentConfig =
              Vue.options.components[this.mConfig.mpdConfig.component] ||
              Vue.options.components[fieldToCamel(this.mConfig.mpdConfig.component, '-', true)]
            if (!componentConfig) {
              console.error(`model绑定事件出错，没有找到【${this.mConfig.mpdConfig.component}】，请检查对应配置`)
            }
            const componentModel = componentConfig.extendOptions.model
            // 处理默认的v-model，其它当作sync修饰符处理
            const eventKey = key === componentModel.prop ? componentModel.event : 'update:' + key
            // 拆解配置的变量
            const lastIndex = element.lastIndexOf('.')
            const targetObj = element.substr(0, lastIndex)
            const targetKey = element.substr(lastIndex + 1)
            newEventObj[eventKey] = value => {
              eval(`this.$set(${targetObj},'${targetKey}',value)`)
            }
          }
        } catch (exception) {
          console.error('model绑定事件值转换错误(这个错误可以忽略)', this.mConfig, exception)
        }
      }
      return newEventObj
    }
  },
  methods: {
    // 转换v-if和v-show指令
    mpdTransformIfOrShowHandle(value) {
      if (value) {
        try {
          return eval(value)
        } catch (error) {
          console.error('v-if或v-show值转换错误（可以忽略）', error)
        }
      }
      return true
    }
  }
}
</script>
